import { Root } from "../../../../../Core/Module/Entity/Root";
import { EventSystem } from "../../../../../Core/Module/EventSystem/EventSystem";
import { Awake1System, AwakeSystem } from "../../../../../Core/Module/EventSystem/IAwakeSystem";
import { DestroySystem } from "../../../../../Core/Module/EventSystem/IDestroySystem";
import { ServiceType } from "../../../../../Core/Module/Network/AService";
import { NetServices } from "../../../../../Core/Module/Network/NetServices";
import { WService } from "../../../../../Core/Module/Network/WService";
import { TimeHelper } from "../../../../../Core/Module/Time/TimeHelper";
import { ExpandOf, FriendOf, ObjectSystemAttribute } from "../../../../../Decorator/Decorator";
import { StartProcessConfigCategory } from "../../../../Model/Generate/Server/Config/StartProcessConfig";
import { NetInnerComponent, NetInnerComponentOnRead } from "../../../../Model/Server/Module/Message/NetInnerComponent";
import { Session } from "../../../../Model/Share/Module/Message/Session";

/**
 * 使用 Expand 扩展方法
 * 
 * 必须作出以下申明，才能调用对象的扩展方法
 */
declare module "../../../../Model/Server/Module/Message/NetInnerComponent" {

    interface NetInnerComponent {

        OnRead(channelId: number, actorId: number, message: Object): void;
        HandleMessage(actorId: number, message: Object): void;
        OnError(channelId: number, error: number): void;
        OnAccept(channelId: number, ipEndPoint: string): void;
        CreateInner(channelId: number, ipEndPoint: string): Promise<Session>;
        Get(channelId: number): Promise<Session>;

    }

}

@ExpandOf(NetInnerComponent)
export class NetInnerComponentSystem {

    private static OnRead(self: NetInnerComponent, channelId: number, actorId: number, message: Object): void {
        let session = self.GetChild<Session>(channelId);
        if (session == null) {
            return;
        }

        session.LastRecvTime = TimeHelper.ClientFrameTime();

        self.HandleMessage(actorId, message);
    }

    private static HandleMessage(self: NetInnerComponent, actorId: number, message: Object): void {
        let netInnerComponentOnRead = new NetInnerComponentOnRead();
        {
            netInnerComponentOnRead.ActorId = actorId;
            netInnerComponentOnRead.Message = message;
        }
        EventSystem.Instance.Publish(Root.Instance.Scene, netInnerComponentOnRead);
    }

    private static OnError(self: NetInnerComponent, channelId: number, error: number): void {
        let session = self.GetChild<Session>(channelId);
        if (session == null) {
            return;
        }

        session.Error = error;
        session.Dispose();
    }

    // 这个channelId是由CreateAcceptChannelId生成的
    private static OnAccept(self: NetInnerComponent, channelId: number, ipEndPoint: string): void {
        let session = self.AddChildWithId<Session, number>(Session, channelId, self.ServiceId);
        session.RemoteAddress = ipEndPoint;
        //session.AddComponent<SessionIdleCheckerComponent, int, int, int>(NetThreadComponent.checkInteral, NetThreadComponent.recvMaxIdleTime, NetThreadComponent.sendMaxIdleTime);
    }

    private static async CreateInner(self: NetInnerComponent, channelId: number, ipEndPoint: string): Promise<Session> {
        let session = self.AddChildWithId<Session, number>(Session, channelId, self.ServiceId);
        session.RemoteAddress = ipEndPoint;
        await NetServices.Instance.CreateChannel(self.ServiceId, channelId, ipEndPoint);

        //session.AddComponent<InnerPingComponent>();
        //session.AddComponent<SessionIdleCheckerComponent, int, int, int>(NetThreadComponent.checkInteral, NetThreadComponent.recvMaxIdleTime, NetThreadComponent.sendMaxIdleTime);

        return session;
    }

    // 内网actor session，channelId是进程号
    private static async Get(self: NetInnerComponent, channelId: number): Promise<Session> {
        let session = self.GetChild<Session>(channelId);
        if (session != null) {
            return session;
        }
        let ipEndPoint = `ws://${StartProcessConfigCategory.Instance.Get(channelId).InnerIPPort}`;
        session = await self.CreateInner(channelId, ipEndPoint);
        return session;
    }

}

@FriendOf(NetInnerComponent)
@ObjectSystemAttribute()
export class NetInnerComponentAwakeSystem extends AwakeSystem<NetInnerComponent> {

    Awake(self: NetInnerComponent): void {
        NetInnerComponent.Instance = self;

        self.ServiceId = NetServices.Instance.AddService(new WService(undefined, ServiceType.Inner));

        NetServices.Instance.RegisterReadCallback(self.ServiceId, self.OnRead.bind(self));
        NetServices.Instance.RegisterErrorCallback(self.ServiceId, self.OnError.bind(self));

        // console.log(`NetInnerComponentAwakeSystem self.ServicedId = ${self.ServiceId}`);
    }

}

@FriendOf(NetInnerComponent)
@ObjectSystemAttribute()
export class NetInnerComponentAwake1System extends Awake1System<NetInnerComponent, string> {

    Awake(self: NetInnerComponent, address: string): void {
        NetInnerComponent.Instance = self;

        self.ServiceId = NetServices.Instance.AddService(new WService(address, ServiceType.Inner));

        NetServices.Instance.RegisterAcceptCallback(self.ServiceId, self.OnAccept.bind(self));
        NetServices.Instance.RegisterReadCallback(self.ServiceId, self.OnRead.bind(self));
        NetServices.Instance.RegisterErrorCallback(self.ServiceId, self.OnError.bind(self));

        // console.log(`NetInnerComponentAwake1System self.ServicedId = ${self.ServiceId}`);
    }

}

@FriendOf(NetInnerComponent)
@ObjectSystemAttribute()
export class NetInnerComponentDestroySystem extends DestroySystem<NetInnerComponent> {

    Destroy(self: NetInnerComponent): void {
        NetServices.Instance.RemoveService(self.ServiceId);
    }

}